package com.RBGame;


import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.content.res.Resources;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class GameView extends View {

    public int mXOffset,mYOffset;
    private int selDot = -1;
    public Graph graph = new Graph();    
    public int viewwidth=0;
    public int viewheight = 0 ;
    public void newGraph() {
    	viewwidth = this.getWidth();
    	viewheight = this.getHeight();
    	mlevelNameText.setText(String.valueOf(levelA)+":"+String.valueOf(levelB));
    	graph = new Graph( levelA, levelB,this.getWidth(), this.getHeight(), Consts.default_gen_range_scale,this.getResources());
    	
    }
    public int fireState = 0;
    public int moveState = 0;
    public boolean firebool = false;
    public int levelA = 1 ;
    public int levelB = 1;
    private int matchwidth = 0; 
    private int matchheight = 0 ;
    public OnClickListener myButtonListener = new OnClickListener () {
    
   	 public void onClick(View v) {
   		  if (v.getId() == R.id.undo_button)
   			  undo();
   		  if (v.getId() == R.id.newgamebutton)
   			  resetgame(); 
   		  if (v.getId() == R.id.prev_button)
   			  goprevlevel();
   		  if (v.getId() == R.id.next_button)
   			  gonextlevel();
   		  if (v.getId() == R.id.next_ten)
   			  gonext10level();
   		  if (v.getId() ==R.id.prev_ten)
   			  goprev10level();
   	 }
   	
   };

   private void resetgame() {
	   checkprevnextEnabled();
       initNewGame();
   }
   private void goprevlevel() {
	   System.out.println("this is go prev");
	   levelB--;
      resetgame();
   }
   private void goprev10level() {
	   //System.out.println("this is go prev"+cnt);
	   levelB-=10;
      resetgame();
   }
   
   private void gonextlevel() {
	   System.out.println("this is go next");
      levelB++;
      resetgame();
   }

   private void gonext10level() {
	   //System.out.println("this is go next"+cnt);
      levelB=levelB+10;
      resetgame();
   }
    private boolean touch_on_match = false;
    private double  mtX0,mtY0,mtX,mtY;
    private boolean enablereverse = false;
    private Timer timerwait = new Timer();
    OnTouchListener myListener= new OnTouchListener() {

        private double pX = 0.0 , pY = 0.0;
        public boolean onTouch(View v, MotionEvent event) {
        if (moveState!=0 || fireState!=0) return true;
       	switch(event.getAction()) {
       	        
      	  		case MotionEvent.ACTION_DOWN: 
      	  				pX = event.getX();
      	  				pY = event.getY();
      	  				selDot = getNearestByXY(pX,pY);
      	  				if (selDot<0) {
      	  					//System.out.println(pX+" "+pY);
      	  					break;
      	  				}
      	  				timerwait = new Timer();
      	  			 enablereverse = true;
      	  			timerwait.schedule(new TimerTaskClass(Consts.WAIT_CLICK_SIGNAL, handler), Consts.max_click_time,Consts.max_click_time);
      	  				invalidate();
      	  				
      	  				break;
      	  		case MotionEvent.ACTION_UP:
      	  				int dX = (int) (event.getX()-pX);
      	  				int dY = (int) (event.getY()-pY);
      	  				if (selDot>=0 && enablereverse)
      	  				if (dX*dX+dY*dY < Consts.max_touch_movedistance_square ) {
      	  					tryReverseByXY(pX,pY);
      	  		//			System.out.println(v.getHeight());
      	  				}
      	  				invalidate();
      	  				selDot = -1;

      	  				if (graph.isEmpty) break;
      	  				timerwait.cancel();
  	  				  break;
      	  		case MotionEvent.ACTION_MOVE:
      	  			if (selDot>=0) {
      	  			   float gX = event.getX();
      	  			   float gY = event.getY();
      	  			   if (gX < 3.0) gX = (float) 3.0; else 
      	  			   if (gX > viewwidth-3.0) gX = (float) (viewwidth - 3.0);
      	  			   if (gY < 3.0) gY = (float) 3.0; else 
       	  			   if (gY > viewheight-3.0) gY = (float) (viewheight - 3.0);
       	  			   
      	  			   graph.setXY(selDot,gX,gY);
      	  			   
      	  			}
      	  			invalidate();
      	  		   
      	  		}
      
       	return true;
        }
        
        private Timer timer = new Timer();  
        
        Handler handler = new Handler(){  
            public void handleMessage(Message msg) {  
            	if (msg.what == Consts.WAIT_CLICK_SIGNAL ) {
            	//   System.out.println("add1");
            	   enablereverse = false;
            	   timerwait.cancel();
            	   return ;
            	}
                if (msg.what<200) {
                  if (msg.what<100) 
                  {
                	  if (moveState < Consts.max_move_time) moveState++;
                	  else fireState++;
                	  if (fireState >= Consts.max_fire_time) { 
                	      firebool = false;
                	      graph.removeDot(msg.what);
                	      checkUndoEnabled();
                	  }
                	  if (!firebool){
                		  fireState = 0;
                		  moveState = 0 ;
                		  selDot = -1;
                		  timer.cancel();
                	  }
                  }  
                }
                invalidate();
                super.handleMessage(msg);                  
            }  
              
        };  
        
        
		private void tryReverseByXY(double pX2, double pY2) {
			checkUndoEnabled();
		    if (firebool) return;
		    if (graph.matchnow==0) return ;
	    	mMatchLeftText.setText(String.valueOf(graph.matchnow-1));
			int who = graph.setStateByXY((int) pX2, (int) pY2,2);
			if (who >=0) {
	    		timer = new Timer();
	    		timer.schedule(new TimerTaskClass(who, handler), Consts.wait_time_ms,Consts.wait_time_ms);
	    		firebool = true;
			}
		}
        private int getNearestByXY(double x, double y) {
           return graph.getNearestByXY((int) x, (int) y);
        }
    	
    };
    public void undo() {
       mStatusText.setVisibility(INVISIBLE);
       graph.undo();
       invalidate();
       checkUndoEnabled();
    }
    
    private static final int RED_STAR = 3;
    private static final int YELLOW_STAR = 2;
    private static final int GREEN_STAR = 1;
    private static final int ORANGE_STAR = 7;
    private static final int FIRE_1 = 4;
    private static final int FIRE_2 = 5;
    private static final int MATCH = 6;
    private TextView mStatusText;
    private TextView mMatchLeftText;
    private TextView mlevelNameText;
    private Button  mUndoButton;
    private Button  mNewgameButton;
    //private Button  mRedoButton;
    private Button  mNextButton;
    private Button  mPrevButton;
    private Button  mNext10Button;
    private Button  mPrev10Button;
    
    public Bitmap[] mTileArray; 
    
    public void setTextView(TextView newView) {
        mStatusText = newView;
    }
    public void setUndoButton(Button newButton) {
    	System.out.println("here set undobutton");
        mUndoButton = newButton;
    }

    public GameView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GameView);
        a.recycle();
        initSnakeView();
   }

	public GameView(Context context, AttributeSet attrs, int defStyle) {
    	super(context, attrs, defStyle);
    	TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GameView);
        a.recycle();
    	initSnakeView();
    }
	private int fire_dx;
	private int fire_dy;
    private void initSnakeView() {
        setFocusable(true);
        
        Resources r = this.getContext().getResources();
        
        resetTiles(8);
        loadTile(ORANGE_STAR, r.getDrawable(R.drawable.orangestar));
        loadTile(RED_STAR, r.getDrawable(R.drawable.redstar));
        loadTile(YELLOW_STAR, r.getDrawable(R.drawable.yellowstar));
        loadTile(GREEN_STAR, r.getDrawable(R.drawable.greenstar));
        
        loadTile(FIRE_1,r.getDrawable(R.drawable.fire1));
        loadTile(FIRE_2,r.getDrawable(R.drawable.fire2));
        loadTile(MATCH,r.getDrawable(R.drawable.matchlogo));
        fire_dx = -mTileArray[FIRE_1].getWidth() / 2;
        fire_dy = -mTileArray[FIRE_1].getHeight();
        mXOffset = Consts.mTileSize/2;
        mYOffset = Consts.mTileSize/2;
        
    	this.setOnTouchListener(myListener);
    	//this.set
    }
    


    public void loadTile(int key, Drawable tile) {
    	int sizeX = Consts.mTileSize;
    	int sizeY = Consts.mTileSize;
    	if (key ==FIRE_1 || key == FIRE_2 ) sizeY = sizeY *3/2;
    	if (key ==MATCH) { sizeY = sizeY * 2; sizeX = sizeY*184/300;
    	            matchwidth = sizeX; matchheight = sizeY;} 
        Bitmap bitmap = Bitmap.createBitmap(sizeX, sizeY, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        tile.setBounds(0, 0, sizeX, sizeY);
        tile.draw(canvas);
        mTileArray[key] = bitmap;
    }

    
    public void resetTiles(int tilecount) {
    	mTileArray = new Bitmap[tilecount];
    }

    
    public void initNewGame() {
    	checkprevnextEnabled();
        this.setOnTouchListener(myListener);
        this.setVisibility(VISIBLE);
        mStatusText.setVisibility(INVISIBLE);
        //System.out.println("init new game"+ this.getWidth());
        if (this.getWidth()!=0)
           newGraph();
        checkUndoEnabled();
        invalidate();
    }


    /**
     * Given a ArrayList of coordinates, we need to flatten them into an array of
     * ints before we can stuff them into a map for flattening and storage.
     * 
     * @param cvec : a ArrayList of Coordinate objects
     * @return : a simple array containing the x/y values of the coordinates
     * as [x1,y1,x2,y2,x3,y3...]
     */
    private int[] coordArrayListToArray(ArrayList<PairInt> cvec) {
        int count = cvec.size();
        int[] rawArray = new int[count * 2];
        for (int index = 0; index < count; index++) {
            PairInt c = cvec.get(index);
            rawArray[2 * index] = c.x;
            rawArray[2 * index + 1] = c.y;
        }
        return rawArray;
    }

    public Bundle saveState() {
        Bundle map = new Bundle();
        map.putIntArray("dotX", graph.dotX);
        map.putIntArray("dotY", graph.dotY);
        map.putIntArray("dotState", graph.dotState);
        
        
/*
        map.putIntArray("mAppleList", coordArrayListToArray(mAppleList));
        map.putInt("mDirection", Integer.valueOf(mDirection));
        map.putInt("mNextDirection", Integer.valueOf(mNextDirection));
        map.putLong("mMoveDelay", Long.valueOf(mMoveDelay));
        map.putLong("mScore", Long.valueOf(mScore));
        map.putIntArray("mSnakeTrail", coordArrayListToArray(mSnakeTrail));
*/
        return map;
    }

    /**
     * Given a flattened array of ordinate pairs, we reconstitute them into a
     * ArrayList of Coordinate objects
     * 
     * @param rawArray : [x1,y1,x2,y2,...]
     * @return a ArrayList of Coordinates
     */
    private ArrayList<PairInt> coordArrayToArrayList(final int[] rawArray) {
        ArrayList<PairInt> coordArrayList = new ArrayList<PairInt>();

        int coordCount = rawArray.length;
        for (int index = 0; index < coordCount; index += 2) {
        	PairInt c = new PairInt(rawArray[index], rawArray[index + 1]);
            coordArrayList.add(c);
        }
        return coordArrayList;
    }

    /**
     * Restore game state if our process is being relaunched
     * 
     * @param icicle a Bundle containing the game state
     */
    public void restoreState(Bundle icicle) {
      //  setMode(PAUSE);
/*
        mAppleList = coordArrayToArrayList(icicle.getIntArray("mAppleList"));
        mDirection = icicle.getInt("mDirection");
        mNextDirection = icicle.getInt("mNextDirection");
        mMoveDelay = icicle.getLong("mMoveDelay");
        mScore = icicle.getLong("mScore");
        mSnakeTrail = coordArrayToArrayList(icicle.getIntArray("mSnakeTrail"));
  */  }

   
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent msg) {
 return super.onKeyDown(keyCode, msg);
    }
    
    
    /*
    public void setMode(int newMode) {
        int oldMode = mMode;
        mMode = newMode;
        this.setOnTouchListener(myListener);
        if (newMode == RUNNING & oldMode != RUNNING) {
            mStatusText.setVisibility(View.INVISIBLE);
            //update();
            return;
        }

        Resources res = getContext().getResources();
        CharSequence str = "";
        if (newMode == PAUSE) {
            str = res.getText(R.string.mode_pause);
        }
        if (newMode == READY) {
            str = res.getText(R.string.mode_ready);
        }
        if (newMode == LOSE) {
            str = res.getString(R.string.mode_lose_prefix) + mScore
                  + res.getString(R.string.mode_lose_suffix);
        }

        mStatusText.setText(str);
        mStatusText.setVisibility(View.VISIBLE);
        mStatusText.setTextColor(Color.RED);
    }
    */

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint inqPaint = new Paint();
        Paint ouqPaint = new Paint();
        Paint TextPaint = new Paint();
        //inqPaint.setStrokeWidth((float) 1);
        //ouqPaint.setStrokeWidth((float) 1);
        
        TextPaint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
        TextPaint.setTextSize(15);
        TextPaint.setColor(Color.BLUE);
        inqPaint.setARGB(255, Consts.color_in_clique_R, Consts.color_in_clique_G,Consts.color_in_clique_B );
        ouqPaint.setARGB(255, Consts.color_out_clique_R, Consts.color_out_clique_G,Consts.color_out_clique_B );
        //neqPaint.setARGB(255, Consts.color_near_clique_R, Consts.color_near_clique_G,Consts.color_near_clique_B );
        if (!graph.isEmpty) {
        	for (int i = 0 ; i <graph.edgecount; i++) {
            	if (graph.dotState[graph.e1[i]] ==1  && graph.dotState[graph.e2[i]] ==1 )
            		if (graph.e1[i] == selDot || graph.e2[i] == selDot)
            			canvas.drawLine(graph.dotX[graph.e1[i]],graph.dotY[graph.e1[i]],
        				        graph.dotX[graph.e2[i]],graph.dotY[graph.e2[i]],inqPaint);
            		else
            			canvas.drawLine(graph.dotX[graph.e1[i]],graph.dotY[graph.e1[i]],
            				        graph.dotX[graph.e2[i]],graph.dotY[graph.e2[i]],ouqPaint);
            	
            }
        	for (int i = 0 ; i < graph.size; i++)
        		for (int j = 0 ; j < graph.size; j++)
        			if (graph.dotState[j] == 1 && graph.dotState[i] ==2 && graph.map[i][j]==1) {
        				int px = (int) (graph.dotX[i] + (graph.dotX[j] - graph.dotX[i])*fireState / Consts.max_fire_time);
        				int py = (int) (graph.dotY[i] + (graph.dotY[j] - graph.dotY[i])*fireState / Consts.max_fire_time);
        				canvas.drawLine(graph.dotX[j],graph.dotY[j],px,py,ouqPaint);
        				if (fireState > 0 )
        				canvas.drawBitmap(mTileArray[FIRE_1+fireState % 2], px+fire_dx, py+fire_dy,inqPaint);
        			}
        	int id = -1;
        	for (int i = 0 ; i < graph.size; i++)
        		  if (graph.dotState[i] == 2) id = i;
        	
        	if (moveState >0 && moveState < Consts.max_move_time) 
        		canvas.drawBitmap(mTileArray[MATCH], (graph.dotX[id]*moveState+(canvas.getWidth()-matchwidth)*(Consts.max_move_time-moveState))/Consts.max_move_time,
        				                             (graph.dotY[id]*moveState+(canvas.getHeight()-matchheight)*(Consts.max_move_time-moveState))/Consts.max_move_time
        				                           , inqPaint);
        	
        	for (int i = 0; i < graph.size; i++)
      		  if (graph.dotState[i]!=0)	{
        		if(selDot>=0) {
        			int who = 0;
        			if (i==selDot) who = ORANGE_STAR;
        			else if (graph.map[i][selDot]==1)
        				who = RED_STAR;
        				else who=YELLOW_STAR;
        		//p	System.out.println(i+" "+who);
        			 canvas.drawBitmap(mTileArray[who], -mXOffset+graph.dotX[i], 
        				-mYOffset+graph.dotY[i],inqPaint);
        		  }
        		else {
      			  canvas.drawBitmap(mTileArray[YELLOW_STAR], -mXOffset+graph.dotX[i], 
      				-mYOffset+graph.dotY[i],inqPaint);
        		}
        		  canvas.drawText(String.valueOf(graph.deg[i]),-mXOffset/3+graph.dotX[i], 
        				  +mYOffset/3+ graph.dotY[i], TextPaint);
        	}
        }
        
    }
    public void checkprevnextEnabled() {
	   mPrevButton.setEnabled(levelB != 1);
	   mNextButton.setEnabled(levelB != 100);
	   mPrev10Button.setEnabled(levelB>10);
	   mNext10Button.setEnabled(levelB<90);
    }
    public void checkUndoEnabled() {
    //	System.out.println(mUndoButton.isEnabled());
    	mMatchLeftText.setText(String.valueOf(graph.matchnow));
    	mUndoButton.setEnabled((graph.removecount!=0));
    	
    	if (graph.matchnow==0 ) 
    	{
    		mStatusText.setVisibility(VISIBLE);
    		if (graph.isEmpty) { mStatusText.setText("Touch Start to play");return; } 
    	    if (graph.allremovedboolean())
    	    	mStatusText.setText("Pass");
    	    else {
    	       mStatusText.setText("Fail");
    	    }
    	}
    }
	public void setNewGameButton(Button mNewgameButton) {
		this.setmNewgameButton(mNewgameButton);
	}
	public Button getmNewgameButton() {
		return mNewgameButton;
	}
	public void setmNewgameButton(Button mNewgameButton) {
		this.mNewgameButton = mNewgameButton;
	}
	public Button getmNextButton() {
		return mNextButton;
	}
	public void setmNextButton(Button mNextButton) {
		this.mNextButton = mNextButton;
	}
	public Button getmPrevButton() {
		return mPrevButton;
	}
	public void setmPrevButton(Button mPrevButton) {
		this.mPrevButton = mPrevButton;
	}
	public TextView getmMatchLeftText() {
		return mMatchLeftText;
	}
	public void setmMatchLeftText(TextView mMatchLeftText) {
		this.mMatchLeftText = mMatchLeftText;
	}
	public TextView getMlevelNameText() {
		return mlevelNameText;
	}
	public void setMlevelNameText(TextView mlevelNameText) {
		this.mlevelNameText = mlevelNameText;
	}
	public Button getmNext10Button() {
		return mNext10Button;
	}
	public void setmNext10Button(Button mNext10Button) {
		this.mNext10Button = mNext10Button;
	}
	public Button getmPrev10Button() {
		return mPrev10Button;
	}
	public void setmPrev10Button(Button mPrev10Button) {
		this.mPrev10Button = mPrev10Button;
	}

}
